CAM scripting/de

Einführung

Der Arbeitsbereichen CAM bietet Werkzeuge zum Importieren, Erstellen, Ändern und Exportieren von Bearbeitungs-Werkzeugbahnen in FreeCAD. Mit ihnen kann der Anwender bestehende G-code-Programme importieren, visualisieren und modifizieren, Werkzeugbahnen aus 3D-Formen erstellen und diese Werkzeugbahnen in G-code exportieren.

Der Arbeitsbereich CAM befindet sich derzeit in einer frühen Entwicklungsphase und bietet nicht alle erweiterten Funktionen, die in einigen kommerziellen Alternativen zu finden sind. Die Python-Skript-Schnittstelle macht es jedoch einfach, Werkzeuge zu modifizieren oder leistungsfähigere zu entwickeln.

Schnellstart

Die Pfadobjekte von FreeCAD bestehen aus einer Folge von Bewegungsbefehlen. Eine typische Anwendung ist diese:

>>> import Path
>>> c1 = Path.Command("g1x1")
>>> c2 = Path.Command("g1y4")
>>> c3 = Path.Command("g1 x2 y2") # spaces end newlines are ignored
>>> p = Path.Path([c1,c2,c3])
>>> o = App.ActiveDocument.addObject("Path::Feature","mypath")
>>> o.Path = p
>>> print (p.toGCode())

FreeCADs internes G-Code-Format

Es ist wichtig, ein vorläufiges Konzept zu verstehen. Der Großteil der folgenden Implementierung stützt sich stark auf Bewegungsbefehle, die dieselben Namen wie G-Code-Befehle haben, jedoch nicht auf die Implementierung eines bestimmten Controllers ausgerichtet sind. Namen wie 'G0' für 'Schnellbewegung' oder 'G1' für 'Vorschubbewegung' wurden aus Gründen der Leistungsfähigkeit (effizientes Speichern von Dateien) und zur Minimierung des Aufwands für die Übersetzung in andere G-Code-Formate gewählt. Da es in der CNC-Welt Tausende von G-Code-Dialekten gibt, wurde eine stark vereinfachte Untergruppe davon ausgewählt. Man könnte das G-Code-Format von FreeCAD als eine "maschinenunabhängige" Form des G-Codes beschreiben.

Innerhalb von .FCStd-Dateien werden Pfaddaten direkt in diesem G-Code-Format gespeichert.

Alle Übersetzungen von/in Dialekte zu FreeCAD-G-Code erfolgen über Vor- und Nachbearbeitungsskripte. Das bedeutet, dass man, wenn man mit einer Maschine arbeiten möchte, die einen bestimmten LinuxCNC-, Fanuc-, Mitusubishi- oder HAAS-Controller usw. verwendet, einen Nachbearbeitungsprozessor für diesen bestimmten Controller verwendet (oder erstellt, falls nicht vorhanden) muss (siehe Abschnitt "Importieren und Exportieren von G-Code" weiter unten).

G-Code-Referenz

Die folgenden Regeln und Richtlinien definieren den G-Code-Befehlssatz, den FreeCAD intern benutzt:

G0 X2.5 Y0 (Der Befehlsname ist G0, die Argumente sind X=2.5 und Y=0)
G1 X30 (Der Befehlsname ist G1, das einzige Argument its X=30)
G90 (Der Befehlsname ist G90, es gibt keine weiteren Argumente)

Liste der aktuell unterstützten G-Code Befehle

Befehl Beschreibung Unterstützte Argumente Angezeigt
G0 schnelle Bewegung X,Y,Z,A,B,C Rot
G1 normale Bewegung X,Y,Z,A,B,C Grün
G2 Bogen im Uhrzeigersinn X,Y,Z,A,B,C,I,J,K Grün
G3 Bogen gegen den Uhrzeigersinn X,Y,Z,A,B,C,I,J,K Grün
G81, G82, G83 Bohren X,Y,Z,R,Q Rot/Grün
G38.2 Gerade Sondenbewegung (verwendet im Sondenmodus) Z,F Gelb
G90 absolute Koordinaten
G91 relative Koordinaten
(Nachricht) Kommentar

Das Befehlsobjekt

Das Command-Objekt repräsentiert einen G-Code-Befehl. Es hat drei Attribute: Name, Parameters (Parameter) und Placement (Positionierung) sowie zwei Methoden: toGCode() und setFromGCode(). Intern enthält es nur einen Namen und ein Wörterbuch mit Parametern. Der Rest (Positionierung und G-Code) wird anhand dieser Daten berechnet.

>>> import Path
>>> c=Path.Command()
>>> c
Command  ( )
>>> c.Name = "G1"
>>> c
Command G1 ( )
>>> c.Parameters= {"X":1,"Y":0}
>>> c
Command G1 ( X:1 Y:0 )
>>> c.Parameters
{'Y': 0.0, 'X': 1.0}
>>> c.Parameters= {"X":1,"Y":0.5}
>>> c
Command G1 ( X:1 Y:0.5 )
>>> c.toGCode()
'G1X1Y0.5'
>>> c2=Path.Command("G2")
>>> c2
Command G2 ( )
>>> c3=Path.Command("G1",{"X":34,"Y":1.2})
>>> c3
Command G1 ( X:34 Y:1.2 )
>>> c3.Placement
Placement [Pos=(34,1.2,0), Yaw-Pitch-Roll=(0,0,0)]
>>> c3.toGCode()
'G1X34Y1.2'
>>> c3.setFromGCode("G1X1Y0")
>>> c3
Command G1 [ X:1 Y:0 ]
>>> c4 = Path.Command("G1X4Y5")
>>> c4
Command G1 [ X:4 Y:5 ]
>>> p1 = App.Placement()
>>> p1.Base = App.Vector(3,2,1)
>>> p1
Placement [Pos=(3,2,1), Yaw-Pitch-Roll=(0,0,0)]
>>> c5=Path.Command("g1",p1)
>>> c5
Command G1 [ X:3 Y:2 Z:1 ]
>>> p2=App.Placement()
>>> p2.Base = App.Vector(5,0,0)
>>> c5
Command G1 [ X:3 Y:2 Z:1 ]
>>> c5.Placement=p2
>>> c5
Command G1 [ X:5 ]
>>> c5.x
5.0
>>> c5.x=10
>>> c5
Command G1 [ X:10 ]
>>> c5.y=2
>>> c5
Command G1 [ X:10 Y:2 ]

Das Bahnobjekt

Das Pfad-Objekt enthält eine Liste von Befehlen

>>> import Path
>>> c1=Path.Command("g1",{"x":1,"y":0})
>>> c2=Path.Command("g1",{"x":0,"y":2})
>>> p=Path.Path([c1,c2])
>>> p
Path [ size:2 length:3 ]
>>> p.Commands
[Command G1 [ X:1 Y:0 ], Command G1 [ X:0 Y:2 ]]
>>> p.Length
3.0
>>> p.addCommands(c1)
Path [ size:3 length:4 ]
>>> p.toGCode()
'G1X1G1Y2G1X1'

lines = """
G0X-0.5905Y-0.3937S3000M03
G0Z0.125
G1Z-0.004F3
G1X0.9842Y-0.3937F14.17
G1X0.9842Y0.433
G1X-0.5905Y0.433
G1X-0.5905Y-0.3937
G0Z0.5
"""

slines = lines.split('\n')
p = Path.Path()
for line in slines:
    p.addCommands(Path.Command(line))

o = App.ActiveDocument.addObject("Path::Feature","mypath")
o.Path = p

# but you can also create a path directly form a piece of G-code.
# The commands will be created automatically:

p = Path.Path()
p.setFromGCode(lines)

Als Abkürzung kann ein Pfadobjekt auch direkt aus einer vollständigen G-Code-Sequenz erstellt werden. Es wird automatisch in eine Folge von Befehlen unterteilt.

>>> p = Path.Path("G0 X2 Y2 G1 X0 Y2")
>>> p
Path [ size:2 length:2 ]

Die Bahn Funktion

Die Pfadfunktion ist ein FreeCAD-Dokumentobjekt, das einen Pfad enthält und diesen in der 3D-Ansicht darstellt.

>>> pf = App.ActiveDocument.addObject("Path::Feature","mypath")
>>> pf
<Document object>
>>> pf.Path = p
>>> pf.Path
Path [ size:2 length:2 ]

Die Pfad Funktion besitzt auch eine Eigenschaft Positionierung. Ändern des Wertes dieser Positionierung , ändert die Position der Funktion in der 3D Ansicht, obwohl die Pfadinformationen selbst nicht verändert werden. Die Transformation ist rein visuell. Auf diese Weise kann zum Beispiel ein Pfad um eine Fläche herum erstellt werden, die eine bestimmte Ausrichtung auf dem Modell hat, die nicht die gleiche Ausrichtung ist, die das Schneidmaterial auf der CNC Maschine haben wird.

Pfadverbünde können jedoch die Positionierung ihrer Unterelemente nutzen (siehe unten).

Die Werkzeug- und Werkzeugtabellen-Objekte

HINWEIS: Diese Art der Werkzeug-Verwendung ist seit der offiziellen Version 0.19 veraltet. In 0.19 wurde das neue Werkzeugbit-Werkzeug-System implementiert, um dieses ältere, veraltete System zu ersetzen. Daher hat sich die Codierung gegenüber der unten dargestellten geändert. Weitere Informationen findet man auf der Seite CAM Werkzeuge.

Skripten <= 0.18

Das Tool-Objekt enthält die Definitionen eines CNC-Werkzeugs. Das Tooltable-Objekt enthält eine geordnete Liste von Werkzeugen. Werkzeugtabellen werden als Eigenschaft an Path Project-Features angehängt und können auch über die grafische Benutzeroberfläche bearbeitet werden, indem man in der Baumansicht auf ein Projekt doppelklickt und in der sich öffnenden Aufgabenansicht auf die Schaltfläche "Werkzeugtabelle bearbeiten" klickt.

Über diesen Dialog können Werkzeugtabellen aus den Formaten .xml von FreeCAD und .tooltable von HeeksCad importiert und in das Format .xml von FreeCAD exportiert werden.

>>> import Path
>>> t1=Path.Tool()
>>> t1
Tool Default tool
>>> t1.Name = "12.7mm Drill Bit"
>>> t1
Tool 12.7mm Drill Bit
>>> t1.ToolType
'Undefined'
>>> t1.ToolType = "Drill"
>>> t1.Diameter= 12.7
>>> t1.LengthOffset = 127
>>> t1.CuttingEdgeAngle = 59
>>> t1.CuttingEdgeHeight = 50.8
>>> t2 = Path.Tool("my other tool",tooltype="EndMill",diameter=10)
>>> t2
Tool my other tool
>>> t2.Diameter
10.0
>>> table = Path.Tooltable()
>>> table
Tooltable containing 0 tools
>>> table.addTools(t1)
Tooltable containing 1 tools
>>> table.addTools(t2)
Tooltable containing 2 tools
>>> table.Tools
{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}
>>>

Funktionen

Die Pfad Verbund Funktion

Das Ziel dieser Funktion ist es, einen oder mehrere Werkzeugwege zu sammeln und sie mit einer Werkzeugtabelle zu verknüpfen. Die Funktion "Verbund" verhält sich auch wie eine Standard-FreeCAD-Gruppe, sodass man Objekte direkt aus der Baumansicht hinzufügen oder entfernen kann. Es können Elemente auch neu angeordnet werden, indem man in der Baumansicht auf das Verbund-Objekt doppelklickt und dessen Elemente in der sich öffnenden Aufgabenansicht neu anordnet.

>>> import Path
>>> p1 = Path.Path("G1X1")
>>> o1 = App.ActiveDocument.addObject("Path::Feature","path1")
>>> o1.Path=p1
>>> p2 = Path.Path("G1Y1")
>>> o2 = App.ActiveDocument.addObject("Path::Feature","path2")
>>> o2.Path=p2
>>> o3 = App.ActiveDocument.addObject("Path::FeatureCompound","compound")
>>> o3.Group=[o1,o2]

Eine wichtige Funktion von Pfadkomponenten ist die Möglichkeit, die Platzierung ihrer untergeordneten Pfade zu berücksichtigen oder nicht, indem ihre UsePlacements-Eigenschaft auf True oder False gesetzt wird. Wenn nicht, werden die Pfaddaten ihrer untergeordneten Elemente einfach sequenziell hinzugefügt. Wenn True, wird jeder Befehl der untergeordneten Pfade, sofern er Positionsinformationen (G0, G1 usw.) enthält, zunächst durch die Positionierung transformiert, bevor er hinzugefügt wird.

Durch das Erstellen einer Verbindung mit nur einem untergeordneten Pfad kann man daher die Positionierung des untergeordneten Pfads "real" machen (sie wirkt sich auf die Pfaddaten aus).

Die Pfad Projekt Funktion

Das Path-Projekt ist eine erweiterte Form von Verbund, die über einige zusätzliche maschinenbezogene Eigenschaften wie beispielsweise eine Werkzeugtabelle verfügt. Es ist in erster Linie als Hauptobjekttyp gedacht, den man nach Fertigstellung der gesamten Pfadkonfiguration in G-Code exportieren möchten. Das Projekt-Objekt ist nun in Python programmiert, sodass sich sein Erstellungsmechanismus etwas unterscheidet:

>>> from PathScripts import PathProject
>>> o4 = App.ActiveDocument.addObject("Path::FeatureCompoundPython","prj")
>>> PathProject.ObjectPathProject(o4)
>>> o4.Group = [o3]
>>> o4.Tooltable
Tooltable containing 0 tools

Das Path-Modul verfügt außerdem über einen GUI-Werkzeugtabellen-Editor, der aus Python heraus aufgerufen werden kann und ihm ein Objekt mit einer ToolTable-Eigenschaft zur Verfügung stellt:

>>> from PathScripts import TooltableEditor
>>> TooltableEditor.edit(o4)

Pfad aus Form holen

Die Form des Linienzugteils einem normalen Pfadobjekt zuweisen, indem man die Skriptfunktion Path.fromShape() (oder die leistungsstärkere Path.fromShapes()) verwendet. Wenn man ein Linienzugteilobjekt als Parameter angibt, wird dessen Pfad automatisch aus der Form berechnet. Es muss beachtet werden, dass in diesem Fall die Platzierung automatisch auf den ersten Punkt des Linienzugs gesetzt wird und das Objekt daher nicht mehr durch Ändern seiner Positionierung verschoben werden kann. Um es zu verschieben, muss die zugrunde liegende Form selbst verschoben werden.

>>> import Part
>>> import Path
>>> v1 = FreeCAD.Vector(0,0,0)
>>> v2 = FreeCAD.Vector(0,2,0)
>>> v3 = FreeCAD.Vector(2,2,0)
>>> v4 = FreeCAD.Vector(3,3,0)
>>> wire = Part.makePolygon([v1,v2,v3,v4])
>>> o = FreeCAD.ActiveDocument.addObject("Path::Feature","myPath2")
>>> o.Path = Path.fromShape(wire)
>>> FreeCAD.ActiveDocument.recompute()
>>> p =  o.Path
>>> print(p.toGCode())

Python Funktionen

Sowohl Path::Feature als auch Path::FeatureShape verfügen über eine Python-Version mit den Namen Path::FeaturePython bzw. Path::FeatureShapePython, die in Python-Code verwendet werden kann, um daraus abgeleitete, komplexere parametrische Objekte zu erstellen.

G-Code importieren und exportieren

Ursprungsformat

G-Code-Dateien können über die GUI direkt importiert und exportiert werden, indem man die Menüpunkte "Öffnen", "Einfügen" oder "Exportieren" verwendet. Nachdem der Dateiname abgerufen wurde, erscheint ein Dialogfeld, in dem man gefragt wird, welches Verarbeitungsskript verwendet werden soll. Dies kann auch über Python erfolgen:

Pfadinformationen werden in Pfadobjekten unter Verwendung einer Teilmenge des G-Codes gespeichert, die im Abschnitt "FreeCADs internes G-Code-Format" oben beschrieben ist. Diese Teilmenge kann "unverändert" importiert oder exportiert oder in eine für Ihre Maschine geeignete Version des G-Codes konvertiert werden.

Wenn man ein sehr einfaches und standardmäßiges G-Code-Programm hat, das den im Abschnitt "FreeCADs internes G-Code-Format" oben beschriebenen Regeln entspricht, beispielsweise der Bumerang aus cnccookbook, kann es ohne Übersetzung direkt in ein Pfadobjekt importiert werden (dies entspricht der Verwendung der Option "Keine" im GUI-Dialogfeld):

import Path
f = open("/path/to/boomerangv4.ncc")
s = f.read()
p = Path.Path(s)
o = App.ActiveDocument.addObject("Path::Feature","boomerang")
o.Path = p

Auf dieselbe Weise kann man die Pfadinformationen als "agnostischen" G-Code abrufen und manuell in einer Datei speichern:

text = o.Path.toGCode()
print text
myfile = open("/path/to/newfile.ngc")
myfile.write(text)
myfile.close()

Wenn man jedoch eine andere Ausgabe benötigt, muss man diesen agnostischen G-Code in ein für die Maschine geeignetes Format konvertieren. Das ist die Aufgabe von Nachbearbeitungsskripten.

Verwendung von Vor- und Nachbearbeitungsskripten

Wenn man eine G-Code-Datei für eine bestimmte Maschine hat, die nicht den internen Regeln von FreeCAD entspricht, die im Abschnitt "FreeCADs internes G-Code-Format" oben beschrieben sind, kann es sein, dass sie nicht richtig importiert und/oder in der 3D-Ansicht gerendert wird. Um dies zu beheben, muss ein Vorverarbeitungsskript verwendet werden, das das maschinenspezifisches Format in das FreeCAD-Format konvertiert.

Wenn der Name des zu verwendenden Vorverarbeitungsskripts bekannt ist, kann die Datei damit aus der Python-Konsole wie folgt importiert werden:

import example_pre
example_pre.insert("/path/to/myfile.ncc","DocumentName")

Auf dieselbe Weise kann ein Path-Objekt mit einem Postprozessor-Skript wie diesem in G-Code ausgeben werden:

import example_post
example_post.export (myObjectName,"/path/to/outputFile.ncc")

Schreiben von Verarbeitungsskripten

Vor- und Nachbearbeitungsskripte verhalten sich wie andere gängige FreeCAD-Importe/Exporte. Wenn man im Dialogfeld ein Vor-/Nachbearbeitungsskript auswählt, wird der Import-/Exportvorgang an das angegebene Skript weitergeleitet. Vorbearbeitungsskripte müssen mindestens die folgenden Methoden enthalten: open(filename) und insert(filename,docname). Nachbearbeitungsskripte müssen export(objectslist,filename) implementieren.

Skripte werden entweder im Ordner Mod/Path/Path/Post/scripts oder im Makro-Pfadverzeichnis des Benutzers abgelegt. Man kann ihnen einen beliebigen Namen geben, aber gemäß der Konvention und damit sie vom GUI-Dialog ausgewählt werden können, müssen die Namen von Vorverarbeitungsskripten mit „_pre“ und die von Nachverarbeitungsskripten mit „_post“ enden (unbedingt den Unterstrich und keinen Bindestrich verwenden, da Python sie sonst nicht importieren kann). Dies ist ein Beispiel für einen sehr, sehr einfachen Präprozessor. Komplexere Beispiele findet man im Ordner Mod/Path/Path/Post/scripts:

def open(filename):
    gfile = __builtins__.open(filename)
    inputstring = gfile.read()
    # the whole gcode program will come in as one string,
    # for example: "G0 X1 Y1\nG1 X2 Y2"
    output = ""
    # we add a comment
    output += "(This is my first parsed output!)\n"
    # we split the input string by lines
    lines = inputstring.split("\n")
    for line in lines:
        output += line
        # we must insert the "end of line" character again
        # because the split removed it
        output += "\n"
    # another comment
    output += "(End of program)"
    import Path
    p = Path.Path(output)
    myPath = FreeCAD.ActiveDocument.addObject("Path::Feature","Import")
    myPath.Path = p
    FreeCAD.ActiveDocument.recompute()

Vor- und Nachprozessoren funktionieren genau gleich. Sie machen nur das Gegenteil: Die Vorskripte konvertieren von spezifischem G-Code in den "agnostischen" G-Code von FreeCAD, während Nachskripte vom "agnostischen" G-Code von FreeCAD in maschinenspezifischen G-Code konvertieren.

Hinzufügen aller Flächen eines Textform zur Liste der BasisFunktionen einer ProfilVonFlächen Operation

Dieses Beispiel basiert auf einer Diskussion im deutschsprachigen Forum.

Voraussetzungen

Der Code

Der folgende Code fügt dann alle Flächen aus Textform hinzu und erstellt die Pfade:

doc = App.ActiveDocument
list_of_all_element_faces = []
for i, face in enumerate(doc.ShapeString.Shape.Faces):
    list_of_all_element_faces.append('Face' + str(i + 1))

doc.Profile_Faces.Base = [(doc.ShapeString, tuple(list_of_all_element_faces))]
doc.recompute()